package cn.k7g.alloy.utils;

import cn.k7g.alloy.model.DiffResult;
import cn.k7g.alloy.model.DiffUnchangedFunction;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 差值比较工具类
 * @date  2021/2/5 下午1:46
 * @author victor-wu
 */
public class DiffUtil {
    /**
     * 新旧数据的对比计算
     * @param newDataMap 新增的数据列
     * @param oldDataMap 已有的数据列
     * @param unchanged 对比监听器
     *                  unchanged = null 或者返回值为 null 表示未改变使用 oldData,
     *                  返回值不为空, 则表示发生改变, 用返回值
     * @return 对比后的结果
     * @param <K> 唯一标识Key
     * @param <V> 列表的元素
     */
    public static <K, V> DiffResult<V> diffNewOld(Map<K, V> newDataMap, Map<K, V> oldDataMap, @Nullable DiffUnchangedFunction<V, V, V> unchanged) {
        // 新增值
        List<V> addedList = newDataMap.entrySet().stream().filter(item -> !oldDataMap.containsKey(item.getKey())).map(Map.Entry::getValue).collect(Collectors.toList());
        // 删除的值
        List<V> deleteList = new ArrayList<>();
        // 未改变的值
        List<V> unchangedList = new ArrayList<>();
        // 已经改变的值
        List<V> changedList = new ArrayList<>();
        for (Map.Entry<K, V> old : oldDataMap.entrySet()) {
            if (newDataMap.containsKey(old.getKey())) {
                if (unchanged != null) {
                    V apply = unchanged.apply(newDataMap.get(old.getKey()), old.getValue());
                    // apply 返回空 表示old 旧数据未发生改变, 使用旧数据操作
                    if (apply == null) {
                        unchangedList.add(old.getValue());
                    } else {
                        // 表示值已经发生改变, 使用处理后的 new 值
                        changedList.add(apply);
                    }
                } else {
                    unchangedList.add(old.getValue());
                }
            } else {
                deleteList.add(old.getValue());
            }
        }
        DiffResult<V> result = new DiffResult<>();
        result.setAddList(addedList);
        result.setDeleteList(deleteList);
        result.setUnchangedList(unchangedList);
        result.setChangedList(changedList);
        return result;
    }

    /**
     * 新旧数据的对比计算
     * @param newDataList 新增的数据列
     * @param oldDataList 已有的数据列
     * @param key key 的属性方法名称
     * @param unchanged 对比监听器
     * @return 对比后的结果
     * @param <K> 唯一标识Key
     * @param <V> 列表的元素
     */
    public static <K, V> DiffResult<V> diffNewOld(List<V> newDataList, List<V> oldDataList, Function<V, K> key, @Nullable DiffUnchangedFunction<V, V, V> unchanged) {
        Map<K, V> newDataMap = newDataList.stream().collect(Collectors.toMap(key, v -> v, (o1, o2) -> o2));
        Map<K, V> oldDataMap = oldDataList.stream().collect(Collectors.toMap(key, v -> v, (o1, o2) -> o2));
        return diffNewOld(newDataMap, oldDataMap, unchanged);
    }
}
